package com.excilys.formation.project.controllers;

import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.validation.constraints.Min;

import org.joda.time.YearMonth;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.excilys.formation.project.controllers.util.AuthentifiedClientManager;
import com.excilys.formation.project.entities.Client;
import com.excilys.formation.project.entities.Compte;
import com.excilys.formation.project.entities.Operation;
import com.excilys.formation.project.entities.TypeOperation;
import com.excilys.formation.project.services.CompteService;
import com.excilys.formation.project.services.OperationService;

/**
 * Controleur de l'affichage des données des comptes.
 * 
 * @author excilys
 * 
 */
@Controller
@RequestMapping(value = "/secure/compte")
public class CompteController {

	/**
	 * Nombre de virements par page.
	 */
	private static final int OPERATION_PAGE = 30;
	/**
	 * Nombre de mois pour lequels les détails sont accessibles.
	 */
	private static final int NOMBRE_DE_MOIS_AFFICHES = 6;
	/**
	 * Service gérant les opérations.
	 */
	@Autowired
	private OperationService operationService;
	/**
	 * Service gérant les comptes.
	 */
	@Autowired
	private CompteService compteService;
	/**
	 * Gère la récupération du client en session.
	 */
	@Autowired
	private AuthentifiedClientManager authentifiedClientManager;

	@RequestMapping(method = RequestMethod.GET)
	public String getView(final Model model) {
		Client connectedClient = authentifiedClientManager.getSessionClient();
		Set<Compte> sortedComptes = new TreeSet<Compte>(connectedClient.getComptes());

		model.addAttribute("comptes", sortedComptes);
		model.addAttribute(connectedClient);
		Map<String, Double> sumEncoursClient = operationService.getSumEncoursByClient(connectedClient.getId());

		model.addAttribute("encours", sumEncoursClient);

		return "secure/compte/index";
	}

	/**
	 * 
	 * @param numero
	 * @param mois
	 * @param model
	 * @return
	 */
	@RequestMapping(method = RequestMethod.GET, value = "/{numero}/{mois}/export")
	protected String getExcel(@PathVariable String numero, @PathVariable String mois, Model model) {
		YearMonth month = YearMonth.parse(mois);
		List<Operation> compteData = operationService.getOperationsByCompteByYearMonth(numero, month);
		Client connectedClient = authentifiedClientManager.getSessionClient();

		model.addAttribute("client", connectedClient);
		model.addAttribute("compteData", compteData);
		return "excelView";
	}

	/**
	 * 
	 * @param numero
	 *            numéro du compte à afficher
	 * @param model
	 *            instance de ModelMap
	 * @return le chemin vers la jsp
	 */
	@RequestMapping(method = RequestMethod.GET, value = "/{numero}")
	public String showOperations(@PathVariable String numero, Model model) {
		return "redirect:" + numero + "/" + YearMonth.now() + "/0";
	}

	/**
	 * 
	 * @param numero
	 *            numéro du compte à afficher
	 * @param model
	 *            instance de ModelMap
	 * @param mois
	 *            mois à vérifier
	 * @return le chemin vers la jsp
	 */
	@RequestMapping(method = RequestMethod.GET, value = "/{numero}/{mois}")
	public String showOperations(@PathVariable String numero, @PathVariable String mois, Model model) {
		return "redirect:" + mois + "/0";
	}

	/**
	 * 
	 * @param numero
	 *            numéro du compte à afficher
	 * @param model
	 *            instance de ModelMap
	 * @param mois
	 *            mois à vérifier
	 * @param offset
	 *            Décalage par rapport au début de la liste
	 * @return le chemin vers la jsp
	 */
	@RequestMapping(method = RequestMethod.GET, value = "/{numero}/{mois}/{offset}")
	public String showOperations(@PathVariable String numero, @PathVariable String mois, @PathVariable @Min(0) int offset, Model model) {
		Client connectedClient = authentifiedClientManager.getSessionClient();
		Compte compte = compteService.getCompte(numero);
		if (compte.getClient().getId() != connectedClient.getId()) {
			throw new ResourceNotFoundException();
		}
		YearMonth month = YearMonth.parse(mois);
		TypeOperation carte = operationService.getTypeByID(3);
		List<Operation> operations = operationService.getOperationsByCompteByYearMonthExceptType(numero, month, carte, offset, OPERATION_PAGE);
		double sommeCarte = operationService.getSumOperationsByCompteByYearMonthAndType(numero, month, carte);
		// TODO Changer pour prendre des yearMonth
		long nombreOperations = operationService.getCountOperationsByCompteAndTimeIntervalExceptType(numero, month.toInterval(), carte);

		DateTimeFormatter dateFormatter = DateTimeFormat.forStyle("LS");
		dateFormatter = dateFormatter.withLocale(Locale.FRANCE);
		YearMonth[] previousMonths = new YearMonth[NOMBRE_DE_MOIS_AFFICHES];

		for (int i = 0; i < NOMBRE_DE_MOIS_AFFICHES; i++) {
			previousMonths[NOMBRE_DE_MOIS_AFFICHES - i - 1] = YearMonth.now().minusMonths(i);
		}
		model.addAttribute("previousMonths", previousMonths);
		model.addAttribute("dateFormatter", dateFormatter);

		model.addAttribute("currentMonth", month);

		Integer precedent = null;
		Integer suivant = null;
		if (offset != 0) {
			if (offset > OPERATION_PAGE) {
				precedent = offset - OPERATION_PAGE;
			} else {
				precedent = 0;
			}
		}
		if ((offset + OPERATION_PAGE) < nombreOperations) {
			suivant = offset + OPERATION_PAGE;
		}
		model.addAttribute("precedent", precedent);
		model.addAttribute("suivant", suivant);

		model.addAttribute(compte);
		model.addAttribute("operations", operations);
		model.addAttribute("sommeCarte", sommeCarte);
		return "secure/compte";
	}

	@RequestMapping(method = RequestMethod.GET, value = "/carte/{numero}/{mois}")
	public String showCardOperations(@PathVariable String numero, @PathVariable String mois, Model model) {
		return "redirect:" + mois + "/0";
	}

	@RequestMapping(method = RequestMethod.GET, value = "/carte/{numero}/{mois}/{offset}")
	public String showCardOperations(@PathVariable String numero, @PathVariable String mois, @PathVariable @Min(0) int offset, Model model) {
		Client connectedClient = authentifiedClientManager.getSessionClient();
		Compte compte = compteService.getCompte(numero);
		if (compte.getClient().getId() != connectedClient.getId()) {
			throw new ResourceNotFoundException();
		}
		YearMonth month = YearMonth.parse(mois);
		TypeOperation carte = operationService.getTypeByID(3);

		List<Operation> operations = operationService.getOperationsByCompteByYearMonthAndType(numero, month, carte, offset, OPERATION_PAGE);
		DateTimeFormatter dateFormatter = DateTimeFormat.forStyle("LS");
		dateFormatter = dateFormatter.withLocale(Locale.FRANCE);
		YearMonth[] previousMonths = new YearMonth[NOMBRE_DE_MOIS_AFFICHES];
		long nombreOperations = operationService.getCountOperationsByCompteAndTimeIntervalExceptType(numero, month.toInterval(), carte);

		Integer precedent = null;
		Integer suivant = null;
		if (offset != 0) {
			if (offset > OPERATION_PAGE) {
				precedent = offset - OPERATION_PAGE;
			} else {
				precedent = 0;
			}
		}
		if ((offset + OPERATION_PAGE) < nombreOperations) {
			suivant = offset + OPERATION_PAGE;
		}
		model.addAttribute("precedent", precedent);
		model.addAttribute("suivant", suivant);

		for (int i = 0; i < NOMBRE_DE_MOIS_AFFICHES; i++) {
			previousMonths[NOMBRE_DE_MOIS_AFFICHES - i - 1] = YearMonth.now().minusMonths(i);
		}
		model.addAttribute("previousMonths", previousMonths);
		model.addAttribute("dateFormatter", dateFormatter);

		model.addAttribute("currentMonth", month);

		model.addAttribute(compte);
		model.addAttribute("operations", operations);
		return "secure/compte";
	}
}
